GDK W32: More flexible modal operation mode
authorРуслан Ижбулатов <lrn1986@gmail.com>
Fri, 11 Aug 2017 07:00:41 +0000 (07:00 +0000)
committerРуслан Ижбулатов <lrn1986@gmail.com>
Sat, 25 Nov 2017 15:44:36 +0000 (15:44 +0000)
Instead of using a boolean to indicate a modal operation being in progress,
use a set of flags, and allow these to be set and unset independently.

Specifically, this allows WM_CAPTURECHANGED handler to only act when a drag-move or
drag-resize modal operation is in progress, and ignore DND (which can also cause
WM_CAPTURECHANGED to be posted). This avoids a crash due to assertion failure when
OLE2 DND code tries to end a modal operation that was already ended by the WM_CAPTURECHANGED
handler.

https://bugzilla.gnome.org/show_bug.cgi?id=786121

gdk/win32/gdkdevicemanager-win32.c
gdk/win32/gdkdnd-win32.c
gdk/win32/gdkevents-win32.c
gdk/win32/gdkglobals-win32.c
gdk/win32/gdkprivate-win32.h

index c4740747ace14de0d4e2a2413a285c61734dddce..830f5131c69f2bdd4197fe8507efe1b0ca209d39 100644 (file)
@@ -1041,7 +1041,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
       /* Don't produce any button or motion events while a window is being
        * moved or resized, see bug #151090.
        */
-      if (_modal_operation_in_progress)
+      if (_modal_operation_in_progress & GDK_WIN32_MODAL_OP_SIZEMOVE_MASK)
         {
           GDK_NOTE (EVENTS_OR_INPUT, g_print ("... ignored when moving/sizing\n"));
           return FALSE;
index cec3dcc763963f1d7cabbc987f98553dc6044033..e2cd1ba75e456b7b70dc970b0d36cbdbf7da2877 100644 (file)
@@ -1896,11 +1896,11 @@ _gdk_win32_dnd_do_dragdrop (void)
 
       GDK_NOTE (DND, g_print ("Calling DoDragDrop\n"));
 
-      _gdk_win32_begin_modal_call ();
+      _gdk_win32_begin_modal_call (GDK_WIN32_MODAL_OP_DND);
       hr = DoDragDrop (&dobj->ido, &pending_src_context->ids,
                       DROPEFFECT_COPY | DROPEFFECT_MOVE,
                       &dwEffect);
-      _gdk_win32_end_modal_call ();
+      _gdk_win32_end_modal_call (GDK_WIN32_MODAL_OP_DND);
 
       GDK_NOTE (DND, g_print ("DoDragDrop returned %s\n",
                              (hr == DRAGDROP_S_DROP ? "DRAGDROP_S_DROP" :
index 9f77a28e30f34873144310514e7f333022f67e83..8066fabec1c78a6e1e5ff14c228fab8060023a19 100644 (file)
@@ -1736,36 +1736,42 @@ modal_timer_proc (HWND     hwnd,
 {
   int arbitrary_limit = 10;
 
-  while (_modal_operation_in_progress &&
+  while (_modal_operation_in_progress != GDK_WIN32_MODAL_OP_NONE &&
         g_main_context_pending (NULL) &&
         arbitrary_limit--)
     g_main_context_iteration (NULL, FALSE);
 }
 
 void
-_gdk_win32_begin_modal_call (void)
+_gdk_win32_begin_modal_call (GdkWin32ModalOpKind kind)
 {
-  g_assert (!_modal_operation_in_progress);
+  GdkWin32ModalOpKind was = _modal_operation_in_progress;
+  g_assert (!(_modal_operation_in_progress & kind));
 
-  _modal_operation_in_progress = TRUE;
+  _modal_operation_in_progress |= kind;
 
-  modal_timer = SetTimer (NULL, 0, 10, modal_timer_proc);
-  if (modal_timer == 0)
-    WIN32_API_FAILED ("SetTimer");
+  if (was == GDK_WIN32_MODAL_OP_NONE)
+    {
+      modal_timer = SetTimer (NULL, 0, 10, modal_timer_proc);
+
+      if (modal_timer == 0)
+       WIN32_API_FAILED ("SetTimer");
+    }
 }
 
 void
-_gdk_win32_end_modal_call (void)
+_gdk_win32_end_modal_call (GdkWin32ModalOpKind kind)
 {
-  g_assert (_modal_operation_in_progress);
+  g_assert (_modal_operation_in_progress & kind);
 
-  _modal_operation_in_progress = FALSE;
+  _modal_operation_in_progress &= ~kind;
 
-  if (modal_timer != 0)
+  if (_modal_operation_in_progress == GDK_WIN32_MODAL_OP_NONE &&
+      modal_timer != 0)
     {
       API_CALL (KillTimer, (NULL, modal_timer));
       modal_timer = 0;
-   }
+    }
 }
 
 static VOID CALLBACK
@@ -3246,30 +3252,37 @@ gdk_event_translate (MSG  *msg,
       break;
 
     case WM_ENTERSIZEMOVE:
-    case WM_ENTERMENULOOP:
-      if (msg->message == WM_ENTERSIZEMOVE)
-       _modal_move_resize_window = msg->hwnd;
-
-      _gdk_win32_begin_modal_call ();
+      _modal_move_resize_window = msg->hwnd;
+      _gdk_win32_begin_modal_call (GDK_WIN32_MODAL_OP_SIZEMOVE_MASK);
       break;
 
     case WM_EXITSIZEMOVE:
-    case WM_EXITMENULOOP:
-      if (_modal_operation_in_progress)
+      if (_modal_operation_in_progress & GDK_WIN32_MODAL_OP_SIZEMOVE_MASK)
        {
          _modal_move_resize_window = NULL;
-         _gdk_win32_end_modal_call ();
+         _gdk_win32_end_modal_call (GDK_WIN32_MODAL_OP_SIZEMOVE_MASK);
        }
       break;
 
+    case WM_ENTERMENULOOP:
+      _gdk_win32_begin_modal_call (GDK_WIN32_MODAL_OP_MENU);
+      break;
+
+    case WM_EXITMENULOOP:
+      if (_modal_operation_in_progress & GDK_WIN32_MODAL_OP_MENU)
+       _gdk_win32_end_modal_call (GDK_WIN32_MODAL_OP_MENU);
+      break;
+
+      break;
+
     case WM_CAPTURECHANGED:
       /* Sometimes we don't get WM_EXITSIZEMOVE, for instance when you
         select move/size in the menu and then click somewhere without
         moving/resizing. We work around this using WM_CAPTURECHANGED. */
-      if (_modal_operation_in_progress)
+      if (_modal_operation_in_progress & GDK_WIN32_MODAL_OP_SIZEMOVE_MASK)
        {
          _modal_move_resize_window = NULL;
-         _gdk_win32_end_modal_call ();
+         _gdk_win32_end_modal_call (GDK_WIN32_MODAL_OP_SIZEMOVE_MASK);
        }
 
       impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
@@ -3425,7 +3438,7 @@ gdk_event_translate (MSG  *msg,
        }
 
       /* Call modal timer immediate so that we repaint faster after a resize. */
-      if (_modal_operation_in_progress)
+      if (_modal_operation_in_progress & GDK_WIN32_MODAL_OP_SIZEMOVE_MASK)
        modal_timer_proc (0,0,0,0);
 
       /* Claim as handled, so that WM_SIZE and WM_MOVE are avoided */
index cb352a419859281d6504065b56a8dd4b75109551..f16ac48dcc027da7c4916ad02462da21ee58411c 100644 (file)
@@ -73,7 +73,7 @@ GdkWin32DndState  _dnd_source_state = GDK_WIN32_DND_NONE;
 gint             _gdk_input_ignore_wintab = FALSE;
 gint             _gdk_max_colors = 0;
 
-gboolean         _modal_operation_in_progress = FALSE;
+GdkWin32ModalOpKind      _modal_operation_in_progress = GDK_WIN32_MODAL_OP_NONE;
 HWND              _modal_move_resize_window = NULL;
 gboolean         _ignore_destroy_clipboard = FALSE;
 
index 27aec8ebfab71b8e642faba60dcc269dd3e09e8c..8b3310a0ac216a39319017ab076ffa19a5851053 100644 (file)
@@ -343,8 +343,23 @@ void _gdk_win32_ole2_dnd_property_change (GdkAtom       type,
                                          const guchar *data,
                                          gint          nelements);
 
-void  _gdk_win32_begin_modal_call (void);
-void  _gdk_win32_end_modal_call (void);
+typedef enum {
+  GDK_WIN32_MODAL_OP_NONE = 0x0,
+  GDK_WIN32_MODAL_OP_SIZE = 0x1 << 0,
+  GDK_WIN32_MODAL_OP_MOVE = 0x1 << 1,
+  GDK_WIN32_MODAL_OP_MENU = 0x1 << 2,
+  GDK_WIN32_MODAL_OP_DND  = 0x1 << 3
+} GdkWin32ModalOpKind;
+
+#define GDK_WIN32_MODAL_OP_SIZEMOVE_MASK (GDK_WIN32_MODAL_OP_SIZE | GDK_WIN32_MODAL_OP_MOVE)
+
+/* Non-zero while a modal sizing, moving, or dnd operation is in progress */
+extern GdkWin32ModalOpKind _modal_operation_in_progress;
+
+extern HWND            _modal_move_resize_window;
+
+void  _gdk_win32_begin_modal_call (GdkWin32ModalOpKind kind);
+void  _gdk_win32_end_modal_call (GdkWin32ModalOpKind kind);
 
 
 /* Options */
@@ -353,11 +368,6 @@ extern gint                 _gdk_max_colors;
 
 #define GDK_WIN32_COLORMAP_DATA(cmap) ((GdkColormapPrivateWin32 *) GDK_COLORMAP (cmap)->windowing_data)
 
-/* TRUE while a modal sizing, moving, or dnd operation is in progress */
-extern gboolean                _modal_operation_in_progress;
-
-extern HWND            _modal_move_resize_window;
-
 /* TRUE when we are emptying the clipboard ourselves */
 extern gboolean                _ignore_destroy_clipboard;